package com.cyao.core;

import net.greghaines.jesque.Job;
import net.greghaines.jesque.client.Client;

import java.util.Calendar;
import java.util.Date;

/**
 * 定时任务工具类
 *
 * @author Cyao
 */
public class ScheduleUtils {
    /**
     * 创建cron表达式任务
     *
     * @param client
     * @param beanName       调用的service名称
     * @param methodName     调用的方法名
     * @param cronExpression cron表达式
     * @param args           动态参数
     */
    public static void cronEnqueue(Client client, String beanName, String methodName, String cronExpression, Object... args) {
        Job job = createJob(beanName, methodName, cronExpression, args);
        try {
            client.removeDelayedEnqueue(ScheduleJob.QUEUE_NAME, job);
            Date triggerTime = getNextTriggerTime(cronExpression);
            if (null != triggerTime) {
                client.delayedEnqueue(ScheduleJob.QUEUE_NAME, job, triggerTime.getTime());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            client.end();
        }
    }

    /**
     * 删除cron表达式任务
     */
    public static void removeCronEnqueue(Client client, String beanName, String methodName, String cronExpression, Object... args) {
        Job job = createJob(beanName, methodName, cronExpression, args);
        try {
            client.removeDelayedEnqueue(ScheduleJob.QUEUE_NAME, job);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            client.end();
        }
    }

    /**
     * 创建延时执行任务
     *
     * @param client
     * @param beanName    调用的service名称
     * @param methodName  调用的方法名
     * @param triggerTime 执行时间
     * @param args        动态参数
     */
    public static void delayedEnqueue(Client client, String beanName, String methodName, Date triggerTime, Object... args) {
        Job job = createJob(beanName, methodName, null, args);
        try {
            client.removeDelayedEnqueue(ScheduleJob.QUEUE_NAME, job);
            client.delayedEnqueue(ScheduleJob.QUEUE_NAME, job, triggerTime.getTime());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            client.end();
        }
    }

    /**
     * 删除延时任务
     */
    public static void removeDelayedEnqueue(Client client, String beanName, String methodName, Object... args) {
        Job job = createJob(beanName, methodName, null, args);
        try {
            client.removeDelayedEnqueue(ScheduleJob.QUEUE_NAME, job);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            client.end();
        }
    }

    /**
     * 创建循环执行任务
     *
     * @param client
     * @param beanName   调用的service名称
     * @param methodName 调用的方法名
     * @param future     何时开始执行
     * @param frequency  执行频率(毫秒)
     * @param args       动态参数
     */
    public static void recurringEnqueue(Client client, String beanName, String methodName, long future, long frequency, Object... args) {
        Job job = createJob(beanName, methodName, null, args);
        try {
            client.removeRecurringEnqueue(ScheduleJob.QUEUE_NAME, job);
            client.recurringEnqueue(ScheduleJob.QUEUE_NAME, job, future, frequency);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            client.end();
        }
    }

    /**
     * 删除循环任务
     */
    public static void removeRecurringEnqueue(Client client, String beanName, String methodName, Object... args) {
        Job job = createJob(beanName, methodName, null, args);
        try {
            client.removeRecurringEnqueue(ScheduleJob.QUEUE_NAME, job);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            client.end();
        }
    }

    /**
     * 根据给定cron表达式计算下一次触发时间
     *
     * @param cronExpression
     * @return
     */
    public static Date getNextTriggerTime(String cronExpression) {
        try {
            return new CronExpression(cronExpression).getTimeAfter(new Date());
        } catch (Exception ignored) {

        }
        return null;
    }

    /**
     * 根据传入时间点生成cron表达式 例如2018-09-10 16:20:00 转换成 0 20 16 10 9 ? 2018
     *
     * @param triggerTime
     * @return
     */
    public static String createCronExpression(Date triggerTime) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(triggerTime);
        return cal.get(Calendar.SECOND) + " " +
                cal.get(Calendar.MINUTE) + " " +
                cal.get(Calendar.HOUR_OF_DAY) + " " +
                cal.get(Calendar.DATE) + " " +
                (cal.get(Calendar.MONTH) + 1) + " " +
                "? " + cal.get(Calendar.YEAR);
    }

    private static Job createJob(String beanName, String methodName, String cronExpression, Object[] args) {
        ScheduleJob.ScheduleParams params = new ScheduleJob.ScheduleParams();
        if (args.length > 0) {
            int index = 0;
            for (Object arg : args) {
                params.put("arg" + index++, arg);
            }
        }
        if (params.isEmpty()) {
            return new Job("ScheduleJob", beanName, methodName, cronExpression);
        } else {
            return new Job("ScheduleJob", beanName, methodName, cronExpression, params.toJsonString());
        }
    }
}
